package org.visionlibrary.image.filters.adjustement;

import javax.media.jai.TiledImage;

import org.visionlibrary.image.acquisition.ImageFactory;
import org.visionlibrary.image.model.AbstractFilter;
import org.visionlibrary.image.model.FilterTools;


public class WindowLevelAdjuster extends AbstractFilter {
	private int level = 100;
	private int window = 200;

	private int maxValue;
	private int minValue;

	private int maxImagePixelValue;

	private int dspMinValue;
	private int dspMaxValue;

	protected int getNewPixelVal(int value) {
		if (value < dspMinValue)
			return 0;
		else if (value > dspMaxValue)
			return maxImagePixelValue;
		else
			return (int) ((value - level)
					* (((double) maxImagePixelValue / 2.0) / ((double) window / 2.0)) + (double) maxImagePixelValue / 2.0);
	}

	public WindowLevelAdjuster(int level, int window) {
		this.level = level;
		this.window = window;
	}

	@Override
	public TiledImage applyFilter(TiledImage src, TiledImage dest) {
		if (null == src)
			throw new NullPointerException("Source image is null.");

		if (null == dest)
			dest = (new ImageFactory()).createCompatibleImage(src);

		int maxX = src.getWidth();
		int maxY = src.getHeight();

		maxImagePixelValue = (int) Math.pow(2, src.getSampleModel()
				.getSampleSize(0)) - 1;

		maxValue = FilterTools.getMaxPixelValue(src)[0];
		minValue = FilterTools.getMinPixelValue(src)[0];

		dspMinValue = (int) (level - window / 2);
		dspMaxValue = (int) (level + window / 2);

		if (dspMaxValue > maxValue) {
			int difference = Math.abs(dspMaxValue - maxValue);
			dspMaxValue = dspMaxValue - difference;
			dspMinValue = dspMinValue - difference;
		}

		if (dspMinValue < minValue) {
			int difference = Math.abs(minValue - dspMinValue);
			dspMaxValue = dspMaxValue + difference;
			dspMinValue = dspMinValue + difference;
		}

		for (int x = 0; x < maxX; x++)
			for (int y = 0; y < maxY; y++) {
				for (int ch = 0; ch < src.getNumBands(); ch++) {
					int pixel = src.getSample(x, y, ch);
					pixel = getNewPixelVal(pixel);
					dest.setSample(x, y, ch, pixel);
				}
			}

		return dest;
	}
}
